#pragma once

#include "Singleton.h"
#include "MapServerProxy.h"
#include "rpc/RPCActor.h"
#include "struct/teleport.h"

class MapServerMgr : public Singleton<MapServerMgr>
{
public:
	MapServerMgr();
	virtual ~MapServerMgr();

	void LoadMapServerConfig();

	bool RegisterMapServer(uint32 hintServiceId, MapServerProxy* pProxy);
	void RemoveMapServer(MapServerProxy* pProxy);

	void BroadcastServerId2AllMapServer(uint32 serverId) const;

	void BroadcastPacket2AllMapServer(const INetPacket& pck) const;
	void BroadcastPacket2AllMapServer(const INetPacket& pck, const INetPacket& data) const;

	void SendPacket2MapServer(uint32 serviceId, const INetPacket& pck) const;
	void SendPacket2MapServer(InstGUID instGuid, const INetPacket& pck) const;
	void SendPacket2MapServer(Character* pChar, const INetPacket& pck) const;

	void RouteToInstance(InstGUID instGuid, const INetPacket& pck) const;
	void RouteToPlayer(Character* pChar, const INetPacket& pck) const;
	void RPCInvoke2Instance(InstGUID instGuid, const INetPacket& pck,
		const std::function<void(INetStream&, int32, bool)>& cb = nullptr,
		AsyncTaskOwner* owner = nullptr, time_t timeout = DEF_RPC_TIMEOUT) const;
	void RPCInvoke2Player(Character* pChar, const INetPacket& pck,
		const std::function<void(INetStream&, int32, bool)>& cb = nullptr,
		AsyncTaskOwner* owner = nullptr, time_t timeout = DEF_RPC_TIMEOUT) const;
	void RPCReply2Instance(InstGUID instGuid, const INetPacket& pck,
		uint64 sn, int32 err = RPCErrorNone, bool eof = true) const;
	void RPCReply2Player(Character* pChar, const INetPacket& pck,
		uint64 sn, int32 err = RPCErrorNone, bool eof = true) const;

	void SendPacket2CrossServer(InstGUID instGuid, const INetPacket& pck) const;
	void SendPacket2CrossServer4Player(
		Character* pChar, InstGUID instGuid, const INetPacket& pck) const;

	void PackAllMapServerInfos(INetPacket& pck) const;

	void StartWorldMapsOnServer(MapServerProxy* pProxy) const;

	void StartInstance(InstGUID fakeInstGuid,
		ObjGUID instOwner = ObjGUID_NULL, uint32 opCodeResp = OPCODE_NONE,
		uint32 flags = 0, const std::string_view& args = emptyStringView) const;
	void StopInstance(InstGUID instGuid) const;

	void RelocateCharacter(Character* pChar,
		ObjGUID instOwner, InstGUID instGuid, const vector3f1f& pos,
		TeleportType type = TeleportType::SwitchMap, uint32 flags = 0,
		const std::string_view& args = emptyStringView);

	MapServerProxy* GetMapServer(uint32 serviceId) const;
	MapServerProxy* GetMapServer(InstGUID instGuid) const;

private:
	struct MapServerInfo {
		std::unordered_map<uint32, std::unordered_set<uint32>> mapCfgs;
		MapServerProxy* pProxy = NULL;
	};

	const MapServerInfo* GetMapServerInfo(uint32 mapType, uint32 mapId) const;

	std::unordered_map<uint32, MapServerProxy*> m_MapServerMap;
	std::vector<MapServerInfo> m_MapServerInfos;
};

#define sMapServerMgr (*MapServerMgr::instance())
